﻿using System;
using ParserGenerator.Output;

namespace ParserGenerator.ParserConstruction
{
    [Serializable]
    public sealed class ParserAutomatonTextWriter
    {
        public IndentedWriter Writer { get; }

        public ParserAutomatonTextWriter(IndentedWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            Writer = writer;
        }

        private void WriteParserAutomatonState(ParserAutomatonState state)
        {
            if (state == null)
                throw new ArgumentNullException(nameof(state));
            Writer.Write(state.Number);
            if (!state.IsConsistent)
                Writer.Write(" *");
            Writer.Write(" : {0}", state.Symbol);
            Writer.Write("\n{0}\n", new string('-', 40));
            Writer.Write(state.Core);
            ParserAutomatonItemSet closure = state.Core.ComputeClosure();
            if (closure.Count > 0)
            {
                Writer.Write("\n{0}\n", new string('.', 40));
                Writer.Write(closure);
            }
            if (state.Transitions.Count > 0)
            {
                Writer.Write("\n\ntransitions:");
                foreach (ParserAutomatonTransition tran in state.Transitions.Values)
                    Writer.Write("\n  {0}: {1}", tran.Symbol, tran);
            }
            if (state.Reductions.Count > 0)
            {
                Writer.Write("\n\nreductions:");
                foreach (ParserAutomatonReduction reduce in state.Reductions.Values)
                    Writer.Write("\n  {0}", reduce);
            }
            if (state.Predecessors.Count > 0)
            {
                Writer.Write("\n\npredecessors:\n");
                foreach (ParserAutomatonState pred in state.Predecessors)
                    Writer.Write("  {0}", pred.Number);
            }
            if (state.InadequacyNodes.Count > 0)
            {
                foreach (ParserAutomatonInadequacyNode node in state.InadequacyNodes)
                {
                    Writer.Write("\n\n{0}", node.Action.Shift != null ? "shift" : "reduce");
                    Writer.Write("-reduce conflict on {0}:", node.Action.Token);
                    foreach (ParserAutomatonContribution c in node.Action)
                        if (c.IsReduction)
                            Writer.Write("\n  reduce: {0} {{{1}}}", c.AsReduction.Item, node.Action.Token);
                        else
                            foreach (ParserAutomatonItem item in c.AsShift.GetRelatedItems())
                                Writer.Write("\n  shift: {0}", item);
                }
            }
        }

        public void WriteParserAutomaton(ParserAutomaton automaton)
        {
            if (automaton == null)
                throw new ArgumentNullException(nameof(automaton));
            for (int i = 0; i < automaton.States.Count; i++)
            {
                if (i > 0)
                    Writer.Write("\n\n");
                WriteParserAutomatonState(automaton.States[i]);
            }
        }
    }
}
